import {
	constructDialogApi,
	constructFetchApi,
	// constructFsApi, // a local constructFsApi is defined
	constructLoggerApi,
	constructNetworkApi,
	constructNotificationApi,
	constructOsApi,
	// constructPathApi,
	// constructShellApi, // a local custom constructShellApi is defined
	constructSystemInfoApi,
	constructUpdownloadApi,
	// type IClipboard,
	type IDialog,
	type IFetchInternal,
	type ILogger,
	type INetwork,
	type INotification,
	type IOs,
	type IPath,
	type IShell,
	type IShellServer,
	type ISystemInfo,
	type IUpdownload
} from "tauri-api-adapter"
import { type IFetch } from "tauri-api-adapter/client"
import {
	checkPermission,
	type ClipboardPermission,
	type DialogPermission,
	type FetchPermission,
	type NetworkPermission,
	type NotificationPermission,
	type OsPermission,
	// type ShellPermission,
	type SystemInfoPermission,
	type UpdownloadPermission
} from "tauri-api-adapter/permissions"
import type { IUiCustomServer1 } from "../../api/server-types"
import {
	AllKunkunPermission,
	type EventPermission,
	type FsPermissionScoped,
	type KunkunFsPermission,
	type OpenPermissionScoped,
	type SecurityPermission,
	type ShellPermission,
	type ShellPermissionScoped,
	type SystemPermission
} from "../../permissions"
import type { IClipboard, IEvent, IFs, IOpen, ISecurity, ISystem, IToast, IUtils } from "../client"
import { constructClipboardApi } from "./clipboard"
// import type { IDbServer } from "./db"
import { constructEventApi } from "./event"
import { constructFsApi } from "./fs"
import { constructOpenApi } from "./open"
import { constructPathApi } from "./path"
import { constructSecurityAPI } from "./security"
// import type { IFsServer, ISystemServer } from "./server-types"
import { constructShellApi } from "./shell"
import { constructSystemApi } from "./system"
import {
	constructToastApi
	// type IToastServer
} from "./toast"
import {
	constructIframeUiApi
	// type IUiCustomServer,
	// type IUiTemplateServer
} from "./ui"
import { constructUtilsApi } from "./utils"

// export type { IDbServer } from "./db"
export { constructFsApi } from "./fs"
export { constructSystemApi } from "./system"
export {
	constructToastApi
	// type IToastServer
} from "./toast"
export {
	constructIframeUiApi
	// type IUiCustomServer,
	// type IUiTemplateServer
} from "./ui"

// export type IJarvisFullAPI =
// 	// IFullAPI &
// 	ISystemServer & IToastServer & IDbServer & IUiTemplateServer & IUiCustomServer & IFsServer // IFsServer will override some methods in IFullAPI, it's fine because it's a superset
type AllScopedPermissions = FsPermissionScoped | OpenPermissionScoped | ShellPermissionScoped
type AllPermissions = AllKunkunPermission | AllScopedPermissions
function getStringPermissions(permissions: AllPermissions[]): AllKunkunPermission[] {
	return permissions.filter((p) => typeof p === "string") as AllKunkunPermission[]
}

function getObjectPermissions(permissions: AllPermissions[]): AllScopedPermissions[] {
	return permissions.filter((p) => typeof p !== "string")
}

export type IKunkunFullServerAPI = {
	clipboard: IClipboard
	fetch: IFetchInternal
	dialog: IDialog
	event: IEvent
	fs: IFs
	log: ILogger
	path: Omit<IPath, "BaseDirectory"> // BaseDirectory is only on Client side, not on Server side
	notification: INotification
	os: IOs
	updownload: IUpdownload
	sysInfo: ISystemInfo
	network: INetwork
	open: IOpen
	system: ISystem
	toast: IToast
	shell: IShellServer
	iframeUi: IUiCustomServer1
	utils: IUtils
	security: ISecurity
}

/**
 * Construct Jarvis Server API with permissions constraints
 * @param permissions all permissions user has
 * @param extPath absolute path to the extension
 * @returns
 */
export function constructJarvisServerAPIWithPermissions(
	permissions: AllPermissions[],
	extPath: string,
	customFunctions: {
		recordSpawnedProcess: (pid: number) => Promise<void>
		getSpawnedProcesses: () => Promise<number[]>
		paste: (options?: {}) => Promise<void>
	}
): IKunkunFullServerAPI {
	return {
		clipboard: constructClipboardApi(
			getStringPermissions(permissions).filter((p) =>
				p.startsWith("clipboard:")
			) as ClipboardPermission[],
			customFunctions.paste
		),
		fetch: constructFetchApi(
			getStringPermissions(permissions).filter((p) => p.startsWith("fetch:")) as FetchPermission[]
		),
		dialog: constructDialogApi(
			getStringPermissions(permissions).filter((p) => p.startsWith("dialog:")) as DialogPermission[]
		),
		event: constructEventApi(
			getStringPermissions(permissions).filter((p) => p.startsWith("event:")) as EventPermission[]
		), // this one is not from tauri-api-adapter, it's a custom one defined in this project, only limited events are exposed
		fs: constructFsApi(
			(getObjectPermissions(permissions) as FsPermissionScoped[]).filter((p) =>
				p.permission.startsWith("fs:")
			),
			extPath
		),
		log: constructLoggerApi(),
		path: constructPathApi(extPath),
		notification: constructNotificationApi(
			getStringPermissions(permissions).filter((p) =>
				p.startsWith("notification:")
			) as NotificationPermission[]
		),
		os: constructOsApi(
			getStringPermissions(permissions).filter((p) => p.startsWith("os:")) as OsPermission[]
		),
		updownload: constructUpdownloadApi(
			getStringPermissions(permissions).filter((p) =>
				p.startsWith("updownload:")
			) as UpdownloadPermission[]
		),
		network: constructNetworkApi(
			getStringPermissions(permissions).filter((p) =>
				p.startsWith("network:")
			) as NetworkPermission[]
		),
		open: constructOpenApi(
			(getObjectPermissions(permissions) as OpenPermissionScoped[]).filter((p) =>
				p.permission.startsWith("open:")
			),
			extPath
		),
		sysInfo: constructSystemInfoApi(
			getStringPermissions(permissions).filter((p) =>
				p.startsWith("system-info:")
			) as SystemInfoPermission[]
		),
		system: constructSystemApi(
			getStringPermissions(permissions).filter((p) => p.startsWith("system:")) as SystemPermission[]
		),
		toast: constructToastApi(),
		shell: constructShellApi(
			[
				...(getStringPermissions(permissions).filter((p) =>
					p.startsWith("shell:")
				) as ShellPermission[]),
				...(getObjectPermissions(permissions) as ShellPermissionScoped[]).filter((p) =>
					p.permission.startsWith("shell:")
				)
			],
			extPath,
			customFunctions.recordSpawnedProcess,
			customFunctions.getSpawnedProcesses
		),
		iframeUi: constructIframeUiApi(),
		utils: constructUtilsApi(),
		security: constructSecurityAPI(
			getStringPermissions(permissions).filter((p) =>
				p.startsWith("security:")
			) as SecurityPermission[]
		)
	}
}
